from spargameproject.spargame.game.objects import card
from spargameproject.spargame.models import GamePlayer
import random

SINGLE_PLAYER = 'single_player'
EASY = 'easy'
POINTS_MAP = {6: 3, 7: 2}
MULTIPLIER_MAP = {'normal': 1, 'dry': 2, 'show_dry': 4}

def getSparDeck():
  game_deck = card.Deck()
  game_deck.remove(card.Cards.ace_of_spades)
  random.shuffle(game_deck)
  return [play_card for play_card in game_deck if int(play_card.rank.value) >= 6]

def isGreater(card1, card2):
  if not card1:
    return False
  if not card2:
    return True
  if card1.suit != card2.suit:
    return False
  else:
    return card1.rank > card2.rank

def getActiveGamePlayersWithoutObserversAndLosers(game):
  active_game_players = game.getActiveGamePlayers()
  real_active_game_players = []
  observers = game.getMetadata('observers') or set()
  losers = game.getMetadata('lost_players') or []
  observers = observers.union(losers)
  if not observers:
    return active_game_players
  for game_player in active_game_players:
    if not game_player.player.id in observers:
      real_active_game_players.append(game_player)
  return real_active_game_players

def isGameOver(active_game_players):
    for active_game_player in active_game_players:
      if active_game_player.getMetadata('current_cards_left') or (
          active_game_player.getMetadata('standby_cards') or active_game_player.getMetadata('dry_card_indeces')):
        return False
    return True

def determineTurnAndLeadPlayer(active_game_players, player_index, card_to_beat,
                               first_card_played, lead_player_id, game):
  next_index = 0 if player_index == len(active_game_players) - 1 else player_index + 1
  # If already in lead, maintain and rotate turn
  if lead_player_id == active_game_players[player_index].player.id:
    game.setMetadata('card_to_beat', first_card_played)
    return next_index, active_game_players[player_index].player.id, first_card_played
  # If cut, take the lead and turn
  everyone_played = len(game.getMetadata('players_played')) >= (len(active_game_players) - 1)
  if isGreater(first_card_played, card_to_beat):
    game.setMetadata('card_to_beat', first_card_played)
    if everyone_played:
      return player_index, active_game_players[player_index].player.id, first_card_played
    else:
      return next_index, active_game_players[player_index].player.id, first_card_played
  else:
    if everyone_played:
      lead_player_index = (
          [index for (index, gameplayer) in enumerate(active_game_players) if gameplayer.player.id == (
              lead_player_id)][0])
      return lead_player_index, lead_player_id, card_to_beat
  # else move to next player and maintain lead.
  return next_index, lead_player_id, card_to_beat

def updateWinStack(game_player, new_lead_game_player, card_to_beat, sub_type):
  if game_player.player.id != new_lead_game_player.player.id:
    return
  win_stack = new_lead_game_player.getMetadata('win_stack') or []
  dry_win_stack = new_lead_game_player.getMetadata('dry_win_stack') or []
  if (win_stack and (not win_stack[-1].rank.value in [6, 7])) or not card_to_beat.rank.value in [6, 7]:
    win_stack, dry_win_stack = [], []
  if sub_type == 'dry':
    dry_win_stack.append(card_to_beat)
  else:
    win_stack.append(card_to_beat)
  new_lead_game_player.setMetadataWithMap({'win_stack': win_stack, 'dry_win_stack': dry_win_stack})


def updateGameOverWinnerAndPoints(game, lead_player_id, active_game_players,
                               players_played, session):
  if isGameOver(active_game_players):
    # game is over
    game.setMetadata('in_progress', False)
    game.setMetadata('observers', set())
    lead_game_player = GamePlayer.objects.get(game=game, player=lead_player_id)
    win_stack = lead_game_player.getMetadata('win_stack')
    dry_win_stack = lead_game_player.getMetadata('dry_win_stack')
    points = 0;
    for card in win_stack:
      points += POINTS_MAP[card.rank.value] if card.rank.value in POINTS_MAP else 1
    for card in dry_win_stack:
      points += POINTS_MAP[card.rank.value] * MULTIPLIER_MAP['dry'] if card.rank.value in POINTS_MAP else 1
    total_points = (lead_game_player.getMetadata('points') or 0) + points
    lead_game_player.setMetadata('points', total_points)
    total_won = (lead_game_player.getMetadata('won') or 0) + 1
    lead_game_player.setMetadata('won', total_won)
    wins = game.getMetadata('wins') or {}
    wins['session'] = {'winner': lead_player_id, 'points': points}
    game.setMetadata('winner', lead_player_id)
    game.setMetadata('wins', wins)
    scores = game.getMetadata('scores') or {}
    scores[lead_player_id] = {'total_points': total_points, 'total_won': total_won}
    game.setMetadata('scores', scores)

    turn_player = game.getMetadata('last_player')
    turn_player = turn_player if turn_player != lead_player_id else game.getMetadata('next_to_last_player')
    is_bot = GamePlayer.objects.get(player=turn_player, game=game).getMetadata('is_bot')
    turn_player = turn_player if not is_bot else game.creator_player
    game.setMetadata('turn_player', turn_player)
    game.setMetadata('dealer', turn_player)
